home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * Examine each argument given to expandargs()
- * If it is a directory, then expand it
- * to all its component files, recursively
- * till you bottom out.
- * If it is not a directory, then just pass it on.
- *
- * Inputs: routine, argc, argv
- * Outputs: nargc, nargv (calls routine(nargc, nargv))
- * To test: compile with -DTEST
- * define MWC if using Mark Williams C
- * run with a directory as an arg
- * Author: JRB
- * Requirements: Mark Williams C or Alcyon C
- * Wants lots of Dynamic memory. It
- * all depends upon how many files you
- * have. Use the -P option to prune
- * out subdirectories and do things
- * one at a time, if you keep running
- * out of memory.
- * With Mark Williams i use _stksize = 128K
- * With Alcyon i use memory model 2 (half of
- * of avail memory) in GEMSTART.S
- *
- * WARNINGS: Be CAREFUL about the 40 folder bug. Use
- * GEMBOOT or FOLDRXXX when dealing with
- * a deeply nested file structure.
- *
- * Added -P name prune option at the suggestion of dietz@zhmti
- * Multiple -P's may be given on the command line.
- * -P name may be given anywhere on the command line. -P name
- * will prune the subdirectories named as arguement to -P.
- * ie: when the program is decending the file hierarchy it
- * will not visit the pruned branches.
- * NOTE that the option is -P and not -p
- * (-p is a valid sz option).
- * NOTE that the arguement given to -P can be the name
- * of a file or a directory. In case it is a file,
- * that file is skipped.
- *
- */
-
- /*
- * Expand argc, so that the called routine(nargc,nargv) receives only
- * filenames, in nargv[][]
- *
- ************************************************************************
- * *
- * WARNING: Be CAREFUL about the 40 folder bug. Use *
- * GEMBOOT or FOLDRXXX when dealing with *
- * a deeply nested file structure. *
- * *
- ************************************************************************
- *
- * Jwahar R. Bammi
- * usenet: {decvax,cbosgd,sun}!cwruecmp!bammi
- * csnet: bammi@cwru.edu
- * arpa: bammi@cwru.edu
- * compuServe: 71515,155
- *
- */
- #ifdef TEST
- #include <stdio.h>
- #include <osbind.h>
- #include <ctype.h>
- #endif
-
- #ifdef TRUE
- #undef TRUE
- #endif
- #ifdef OK
- #undef OK
- #endif
- #ifdef FALSE
- #undef FALSE
- #endif
-
- #define TRUE 1
- #define OK 0
- #define FALSE 0
- #define Realloc realloc
-
- #ifdef TEST
- struct stat
- {
- char st_sp1[21]; /* Junk */
- char st_mode; /* File attributes */
- int st_time; /* Mod Time */
- int st_date; /* Mod date */
- long st_size; /* File size */
- char st_name[14]; /* File name */
- };
- #endif
-
- typedef struct _prunelist {
- char *name; /* name of subdirectory to prune */
- struct _prunelist *next; /* ptr to next */
- } PRUNELIST;
-
- static char *ProgName;
- static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */
-
- static char **CopyToNargv();
- static char **ExpandStack();
- static void FreeStack();
- static void FreeNargv();
- static void FreePrune();
- static void FreeUp();
- static int PushDir();
- static char *PopDir();
- static int ProcessDirs();
- static PRUNELIST *AddPrune();
- static int OnPruneList();
- static int isdir();
-
- extern int existd();
-
- expandargs(routine, argc, argv)
- int (*routine)();
- int argc;
- char **argv;
- {
- register int status;
- int nargc;
- char **nargv;
- extern char **CopyToNargv();
- extern PRUNELIST *AddPrune();
- extern int existd();
-
- nargc = 0;
- nargv = (char **)NULL;
- ProgName = *argv;
-
- /* copy argv[0] blindly */
- if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL)
- {
- FreeUp(nargc, nargv);
- return(~OK);
- }
-
- nargc++;
-
- while((--argc) > 0)
- {
- argv++;
- if(**argv == '-')
- {
- /* copy any options except -P */
- #ifdef TEST
- /* some shell pass -P as -p */
- if( ((*argv)[1] == 'P') || ((*argv)[1] == 'p'))
- #else
- if( (*argv)[1] == 'P')
- #endif
- {
- if((--argc) <= 0)
- {
- fprintf(stderr,"no argument given to -P\n");
- FreeUp(nargc, nargv);
- return(~OK);
- }
- if((PruneList = AddPrune(PruneList,*++argv))
- == (PRUNELIST *)NULL)
- {
- FreeUp(nargc, nargv);
- return(~OK);
- }
- }
- else
- {
- if((nargv = CopyToNargv(*argv, nargc, nargv))
- == (char **)NULL)
- {
- FreeUp(nargc, nargv);
- return(~OK);
- }
- else
- nargc++;
- }
-
- }
- else
- {
- /* If its not on the PruneList then */
- if(!OnPruneList(PruneList, *argv))
- {
- /* if it is a directory, push it */
- if(existd(*argv))
- {
- if((status = PushDir(*argv)) != OK)
- {
- FreeUp(nargc, nargv);
- return(status);
- }
- }
- else
- {
- /* it is NOT a directory, copy to nargv */
- if((nargv = CopyToNargv(*argv, nargc, nargv))
- == (char **)NULL)
- {
- FreeUp(nargc, nargv);
- return(~OK);
- }
- else
- nargc++;
- }
- }
- }
- } /* while */
-
- /* process pushed directories if any */
- if((status = ProcessDirs(&nargc, &nargv)) != OK)
- {
- FreeUp(nargc, nargv);
- return(status);
- }
- /* else Free the Stack and Prune List, call *routine */
- FreeStack();
- FreePrune();
- status = (*routine)(nargc, nargv);
- FreeNargv(nargc, nargv);
-
- return status;
-
- }
-
- /*
- * Expand nargv by an element and copy a String into the new element
- *
- */
- static char **CopyToNargv(string, nargc, nargv)
- char *string;
- int nargc;
- char **nargv;
- {
- extern char *malloc(), *Realloc(), *strcpy();
- extern int strlen();
-
- /* expand nargv by 1 element */
- if(nargv == (char **)NULL)
- /* do it with malloc for the first one */
- nargv = (char **)malloc(sizeof(char **));
- else
- /* do it with Realloc for others */
- nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **));
-
- if(nargv == (char **)NULL)
- {
- /* failed to get memory */
- fprintf(stderr,"%s(CopyToNargv()): Out of Memory\n", ProgName);
- return ((char **)NULL);
- }
-
- /* Get mem for string */
- if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL)
- {
- /* failed to get memory */
- fprintf(stderr,"%s(CopyToNargv()): Out of Memory\n", ProgName);
- return ((char **)NULL);
- }
-
- /* copy string into nargv[nargc] */
- (void)strcpy( nargv[nargc], string);
- return(nargv);
- }
-
- static char **Stack = (char **)NULL; /* directory stack */
- static char StackSize = 0; /* Size of current Stack */
- static int Top = -1;
- #define STACK_EMPTY (Top < 0)
- #define CHUNKSIZE 16
-
- /*
- * Grow the Stack by one chunk of CHUNKSIZE elements
- *
- */
- static char **ExpandStack(Stack)
- char **Stack;
- {
- extern char *malloc(), *Realloc();
-
- /* Grow Stack */
- if(Stack == (char **)NULL)
- /* with malloc */
- Stack = (char **)malloc(CHUNKSIZE * sizeof(char **));
- else
- /* with Realloc */
- Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) *
- sizeof(char **));
-
- if(Stack == (char **)NULL)
- {
- /* outa mem */
- fprintf(stderr,"%s(ExpandStack()): Out of Memory\n", ProgName);
- return((char **)NULL);
- }
- StackSize += CHUNKSIZE;
- return(Stack);
- }
-
- /*
- * Free the Stack
- *
- */
- static void FreeStack()
- {
- if(StackSize > 0)
- (void)free(Stack);
- Stack = (char **)NULL;
- StackSize = 0;
- Top = -1;
- }
-
- /*
- * Free Nargv
- *
- */
- static void FreeNargv(nargc, nargv)
- int nargc;
- char *nargv[];
- {
- register int i;
-
- for(i = 0; i < nargc; i++)
- (void)free(nargv[i]);
- if(nargc > 0)
- (void)free(nargv);
- }
-
- /*
- * Free the PruneList
- *
- */
- static void FreePrune()
- {
- register PRUNELIST *p, *next;
-
- for(p = PruneList; p != (PRUNELIST *)NULL; p = next)
- {
- next = p->next;
- (void)free(p);
- }
- PruneList = (PRUNELIST *)NULL;
- }
-
- /*
- * FreeUp before bad exit
- *
- */
- static void FreeUp(nargc, nargv)
- int nargc;
- char **nargv;
- {
- FreeStack();
- FreePrune();
- FreeNargv(nargc, nargv);
- }
-
- /*
- * Push a directory name on Stack
- *
- */
- static int PushDir(name)
- char *name;
- {
- extern char *malloc(), *strcpy();
- extern int strlen();
- extern char **ExpandStack();
-
- #ifdef DDEBUG
- printf("PushDir: %s\n", name);
- #endif
-
- ++Top;
- if(Top >= StackSize)
- {
- if((Stack = ExpandStack(Stack)) == (char **)NULL)
- return(~OK);
- }
-
- if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL)
- {
- /* outa mem */
- fprintf(stderr,"%s(PushDir()): Out of Memory\n", ProgName);
- return(~OK);
- }
- (void)strcpy(Stack[Top], name);
- return(OK);
- }
-
- /*
- * Pop a directory name from the stack
- *
- */
- static char *PopDir()
- {
- register char *r;
- extern char **ShrinkStack();
-
- if(STACK_EMPTY)
- return ((char *)NULL);
-
- r = Stack[Top];
- Top--;
- return(r);
- }
-
- static int BadStatus = FALSE;
- #define BADSTATUS (BadStatus != FALSE)
- #define MAXNAMLEN 128
-
- /*
- * Process directories on the Stack, by adding all the
- * files in a directory to nargv.
- */
- static int ProcessDirs(nargc, nargv)
- int *nargc;
- char ***nargv;
- {
- register char *name;
- register struct stat *dp;
- register int status, slashp;
- char path[MAXNAMLEN+1];
- extern char **CopyToNargv();
- extern char *PopDir();
- extern char *alltolower();
-
- if(BADSTATUS)
- return(~OK);
-
- if(STACK_EMPTY)
- /* Nothing more to do */
- return(OK);
-
- /* Pop a directory from Stack and process */
- if((name = PopDir()) == (char *)NULL)
- {
- /* Oh Oh */
- fprintf(stderr,"Internal Error (BUG), PopDir returns NULL\n");
- BadStatus = (~FALSE);
- return(~OK);
- }
-
- strcpy(path, name);
- if(path[(strlen(path)-1)] == '\\')
- {
- strcat(path,"*.*");
- slashp = TRUE;
- }
- else
- {
- strcat(path,"\\*.*");
- slashp = FALSE;
- }
-
- /* Open the directory */
- if(Fsfirst(path, 0x0020| 0x0010 | 0x0001) != 0)
- {
- /* trouble opening directory */
- fprintf(stderr,"Trouble opening %s\n",path);
- /* set BADSTATUS and return */
- BadStatus = (~FALSE);
- return(~OK);
- }
-
- /* get the DTA */
- dp = (struct stat *)Fgetdta();
-
- /* for each entry in the directory, if it is a file
- add to nargv. If it is a directory, Push it onto
- the directory stack.
- */
- do
- {
- if(! ((strcmp(dp->st_name,".") == 0) ||
- (strcmp(dp->st_name,"..") == 0)) )
- {
- strcpy(path, name);
- if(!slashp)
- strcat(path,"\\");
- strcat(path,dp->st_name);
-
- /* If this path is on the PruneList skip */
- if(OnPruneList(PruneList, alltolower(path)))
- continue;
-
- if(!isdir(path, dp->st_mode))
- {
- /* not a dir -- add this to nargv */
- if((*nargv = CopyToNargv(path, *nargc, *nargv))
- == (char **)NULL)
- {
- BadStatus = (~FALSE);
- return(~OK);
- }
- else
- {
- *nargc += 1;
- }
-
- }
- else
- {
-
- /* Push This directory */
- if((status = PushDir(path)) != OK)
- {
- BadStatus = (~FALSE);
- return(status);
- }
- }
- }
- } while(Fsnext() == 0);
-
- free(name); /* done with this directory */
-
- /* go do the rest */
- return (ProcessDirs(nargc, nargv));
- }
-
- /*
- * Add a name to PruneList
- *
- */
- static PRUNELIST *AddPrune(list, name)
- PRUNELIST *list;
- char *name;
- {
- extern char *malloc();
- register PRUNELIST *new;
-
- if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL)
- {
- /* outa mem */
- fprintf(stderr,"%s(AddPrune()): Out of Memory\n", ProgName);
- return(new);
- }
-
- new->name = name;
- new->next = list;
-
- return(new);
- }
-
- /*
- * Search for name on PruneList
- *
- */
- static int OnPruneList(list, name)
- register PRUNELIST *list;
- register char *name;
- {
- for(; list != (PRUNELIST *)NULL; list = list->next)
- {
- if(strcmp(list->name, name) == 0)
- return(~FALSE);
- }
-
- return(FALSE);
- }
-
- /*
- * test if a subdirectory exists, without touching the DTA
- * include special case of 'D:\' that Fsfirst does'nt handle correctly
- */
- static int isdir(name, attr)
- register char *name;
- register int attr;
- {
- /* assuming the DTA buffer is already set up */
- extern long drv_map;
- register int drive;
-
- if(attr & 0x0010)
- return TRUE;
-
- /* Gemdos doesn't like d:\ style dirs */
- if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
- {
- drive = name[0];
- if(isupper(drive))
- drive = tolower(drive);
-
- drive = drive - 'a';
- if((drv_map & (1L << drive)) == 0)
- return FALSE;
- else
- return TRUE;
- }
- /* Nor does Gemdos understand '.' or '..' */
- /* Hey Atari, don't you guys ever test anything */
- if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
- (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
- return TRUE;
-
- return FALSE;
- }
-
-
- #ifdef TEST
-
- /*
- * convert string to all lower case
- */
- char *alltolower(s)
- char *s;
- {
- register char *p;
-
- for(p = s; *p != '\0'; p++)
- if(isupper(*p))
- *p = tolower(*p);
-
- return s;
- }
-
- /*
- * test if a subdirectory exists
- * include special case of 'D:\' that Fsfirst does'nt handle correctly
- * (this routine not needed for zmdm, as it is defined in common.c)
- */
- int existd(name)
- register char *name;
- {
- /* assuming the DTA buffer is already set up */
- /* assumes drv_map has been read in drv_map externally */
- extern long drv_map;
- register int drive;
- extern struct stat statbuf;
-
- if (Fsfirst(name , 0x0021|0x0010) == 0)
- {
- if((statbuf.st_mode & 0x0010) == 0x0010)
- return TRUE;
- }
-
- /* Gemdos doesn't like d:\ style dirs */
- if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
- {
- drive = name[0];
- if(isupper(drive))
- drive = tolower(drive);
-
- drive = drive - 'a';
- if((drv_map & (1L << drive)) == 0)
- return FALSE;
- else
- return TRUE;
- }
- /* Nor does Gemdos understand '.' or '..' */
- /* Hey Atari, don't you guys ever test anything */
- if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
- (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
- return TRUE;
-
- return FALSE;
- }
-
- int MAIN(argc, argv)
- int argc;
- char **argv;
- {
- register int i;
-
- for(i = 0; i < argc; i++)
- printf("%d:\t%s\n", i, argv[i]);
-
-
- return(0);
- }
-
-
- struct stat statbuf; /* Disk Transfer address for Find first etc */
- long drv_map;
-
- #ifdef MWC
- long _stksize = 128L * 1024L;
- #endif
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- /* Set up Dta */
- Fsetdta(&statbuf);
- drv_map = Drvmap();
-
- exit(expandargs(MAIN, argc, argv));
- }
-
- #endif /* TEST */
-